/*****************************************************************//**
 * \file   AnsysDataDef.h
 * \brief  AnsysDataDef
 *
 * \author Wyatt
 * \date   May 2023
 *********************************************************************/
#pragma once

#include "AnsysMeshDef.h"
#include <vector>
#include <set>
#include <unordered_map>
#include <algorithm>
#include <tuple>

#include "Define.h"
#include "Num3.h"
#include "Num6.h"
#include "SimdroidMeshDef.h"

enum DIM_DOF
{
	TX = 0x001,        //! X方向平移 
	TY = 0x002,        //! Y方向平移 
	TZ = 0x004,        //! Z方向平移 
	RX = 0x008,        //! X方向旋转 
	RY = 0x010,        //! Y方向旋转 
	RZ = 0x020,        //! Z方向旋转 
	VX = 0x040,        //! X方向平移速度 
	VY = 0x080,        //! Y方向平移速度 
	VZ = 0x100,        //! Z方向平移速度 
	OX = 0x200,        //! X方向旋转速度 
	OY = 0x400,        //! Y方向旋转速度 
	OZ = 0x800,        //! Z方向旋转速度 
};

enum ANSYS_TB_TYPE
{
	ANSYS_TB_AFDM,
	ANSYS_TB_AHYPER,
	ANSYS_TB_ANEL,
	ANSYS_TB_BB,
	ANSYS_TB_BH,
	ANSYS_TB_BISO,
	ANSYS_TB_BKIN,
	ANSYS_TB_CAST,
	ANSYS_TB_CDM,
	ANSYS_TB_CGCR,
	ANSYS_TB_CHABOCHE,
	ANSYS_TB_COMP,
	ANSYS_TB_CONCR,
	ANSYS_TB_CREEP,
	ANSYS_TB_CTE,
	ANSYS_TB_CZM,
	ANSYS_TB_DENS,
	ANSYS_TB_DISCRETE,
	ANSYS_TB_DMGE,
	ANSYS_TB_DMGI,
	ANSYS_TB_DP,
	ANSYS_TB_DPER,
	ANSYS_TB_EDP,
	ANSYS_TB_ELASTIC,
	ANSYS_TB_EOS,
	ANSYS_TB_EVISC,
	ANSYS_TB_EXPE,
	ANSYS_TB_FCON,
	ANSYS_TB_FCLI,
	ANSYS_TB_FLUID,
	ANSYS_TB_FOAM,
	ANSYS_TB_FRIC,
	ANSYS_TB_GASKET,
	ANSYS_TB_GCAP,
	ANSYS_TB_GURSON,
	ANSYS_TB_HFLM,
	ANSYS_TB_HILL,
	ANSYS_TB_HONEY,
	ANSYS_TB_HYPER,
	ANSYS_TB_INTER,
	ANSYS_TB_JOIN,
	ANSYS_TB_JROCK,
	ANSYS_TB_MC,
	ANSYS_TB_MIGR,
	ANSYS_TB_MOONEY,
	ANSYS_TB_MPLANE,
	ANSYS_TB_NLISO,
	ANSYS_TB_PELAS,
	ANSYS_TB_PERF,
	ANSYS_TB_PIEZ,
	ANSYS_TB_PLASTIC,
	ANSYS_TB_PLAW,
	ANSYS_TB_PM,
	ANSYS_TB_PRONY,
	ANSYS_TB_PZRS,
	ANSYS_TB_RATE,
	ANSYS_TB_SDAMP,
	ANSYS_TB_SHIFT,
	ANSYS_TB_SMA,
	ANSYS_TB_SOIL,
	ANSYS_TB_STATE,
	ANSYS_TB_SWELL,
	ANSYS_TB_THERM,
	ANSYS_TB_UNIAXIAL,
	ANSYS_TB_USER,
	ANSYS_TB_WEAR,

	ANSYS_TB_CNT
};

enum ANSYS_TARGET_TYPE
{
	TARGET_UNKNOWN,
	TARGET_NODE,
	TARGET_ELEM,
	TARGET_SURFACE,
	TARGET_COMPONENT,
};

struct AnsysComponent
{
	std::string comName = "";
	ANSYS_TARGET_TYPE comType = ANSYS_TARGET_TYPE::TARGET_NODE;
	SKey comDataNum;
	std::vector<int> comData;
	std::string prop_name = "";
};

struct AnsysBase
{
	SKey nLine;
	SKey oldId;
	AnsysBase()
	{
		nLine = 0;
		oldId = 0;
	}
};
struct AnsysNode :public AnsysBase
{
	SKey id;
	SNum3d vPos;
	AnsysNode()
	{
		id = 0;
		vPos.setValAll(DEFAUL_DBL);
	}
};
const static int ANSCDB_MAX_ND = 32;
struct AnsysElem :public AnsysBase
{
	SKey id;
	SKey data[ANSCDB_MAX_ND];
	bool bSolid;
	void Init()
	{
		id = 0;
		bSolid = false;
		memset(data, 0, ANSCDB_MAX_ND * sizeof(SKey));
	}
	AnsysElem()
	{
		Init();
	}
};
struct AnsysElement
{
	bool ifOutElment;

	SKey ansysID;
	int solidReference;                  //! if not solid  = -1
	int sectinId;
	int realConstantNum;
	int matNum;
	int elementType;	
	
	int elementCoorNum;
	bool birthOrDeath;	
	int elementShapeFlag;

	int nodesNumInEle;
	std::vector<int> nodeIds;

	void Init()
	{
		ifOutElment = true;
		ansysID = 0;
		solidReference = -1;
		sectinId = 0;
		realConstantNum = 0;
		matNum = 0;
		elementType = 0;
		elementCoorNum = 0;
		birthOrDeath = false;
		elementShapeFlag = 0;
		nodesNumInEle = 0;
		nodeIds.clear();
	}
	AnsysElement()
	{
		Init();
	}
};

struct AnsysTB : public AnsysBase
{
	int mid;
	ANSYS_TB_TYPE TType; // table type
	std::string MType;   // IBE material type
	int DataCnt;
	int TemperatureCnt;

	AnsysTB()
	{
		mid = 0;
		TType = ANSYS_TB_CNT;
		DataCnt = 0;
	}
};
typedef std::tuple<int, int, int, int> AnsysPropTup; // mat id, ele type id, real id, section id
#define getPropInfoMId(prop) std::get<0>(prop)
#define getPropInfoEId(prop) std::get<1>(prop)
#define getPropInfoRId(prop) std::get<2>(prop)
#define getPropInfoSId(prop) std::get<3>(prop)
typedef std::unordered_map <int, AnsysElem> AnsysElemMap;
struct TupleHash4 {
	std::size_t operator()(const AnsysPropTup& t) const {
		std::size_t h = std::hash<int>{}(std::get<0>(t));
		std::size_t h1 = std::hash<int>{}(std::get<1>(t));
		std::size_t h2 = std::hash<int>{}(std::get<2>(t));
		std::size_t h3 = std::hash<int>{}(std::get<3>(t));
		return h ^ (h1 << 1) ^ (h2 << 2) ^ (h3 << 3);
	}
};
typedef std::unordered_map<AnsysPropTup, AnsysElemMap, TupleHash4> AnsysProp;
typedef std::unordered_map<AnsysPropTup, std::vector<int>, TupleHash4> AnsysPropNew;
typedef struct HlpElemProp
{
	SKey id;           // old element id
	AnsysPropTup prop; // element property key
}HlpElemProp;

enum AnsysStepType
{
	UNKNOWN_STEP = -1,
	STATIC,
	BUCKLE,
	MODAL,
	HARMIC,
	TRANS,
	SUBSTR,
	SPECTR,
	SOIL,
	//新增代码-20240506
	UNDETERMINED
};

struct AnsysStep :public AnsysBase
{
	AnsysStepType type = (AnsysStepType)0;
	bool status = true;                //! TRUE:"NEW";FALSE:"RESTART"
	std::string ldStep = "";           //! 好像是用来续算的
	std::string subStep = "";          //! 明确从哪一块开始续算
	std::string action = "";           //! 用来定义续算模块的行为
	bool preLP = false;                //! 后续是否执行线性扰动的标识

	//新增代码20240507
	std::string MatKey = "";
	std::string ContKey = "";
	std::string LoadControl = "";
};

struct AnsysLbcItem :public AnsysBase
{
	std::string itemType;
	SKey id;
	SNum6d v;
	DIM_DOF dof;
	int stepIn;
	ANSYS_TARGET_TYPE tType;
	int faceIndex;
	std::vector<SKey> vecId;
	std::vector<int> vecFaceIndex;
	bool operator==(const AnsysLbcItem& item1) const
	{
		return (item1.v == this->v);
	}
	AnsysLbcItem()
	{
		tType = TARGET_UNKNOWN;
		id = 0;
		faceIndex = -1;
		v.setValAll(DEFAUL_DBL);
	}
};

struct AnsysTargetInfor
{
	int nFieldColumns;
	long nLine;
	std::string setName;
	ANSYS_TARGET_TYPE type;
	AnsysLbcItem item;
	AnsysTargetInfor()
	{
		nLine = 0;
		nFieldColumns = 0;
		type = TARGET_UNKNOWN;
	}
};

struct AnsysSetInfor 
{
	ANSYS_TARGET_TYPE setType;
	std::string setName;
	std::vector<int> outIds;                 //! for node or element
	//std::vector<SurfaceElem> surfaceElement;     //! for surface
};

struct AnsysConnectTarget :public AnsysBase
{
	std::set<SKey> mSet;
	std::set<SKey> sSet;
	int dof;
	SNum6d v;
	AnsysConnectTarget()
	{
		dof = 0;
		v.setValAll(DEFAUL_DBL);
	}
};

struct AnsysMPTEMP :public AnsysBase
{
	std::vector<double>v;
	AnsysMPTEMP()
	{
		v.reserve(6);
	}
	void clear()
	{
		v.clear();
	};
};

struct AnsysRealSet :public AnsysBase
{
	int id;
	double val[150];
	void Init()
	{
		id = 0;
		memset(val, 0, 150 * sizeof(double));
	}
	AnsysRealSet()
	{
		Init();
	}
};

enum ANSYSSEC_TYPE
{
	ANSYS_BEAM,
	ANSYS_TAPER,
	ANSYS_PIPE,
	ANSYS_LINK,
	ANSYS_SHELL,
	ANSYS_UNKNOWN
};

enum ANSYSSEC_SUBTYPE
{
	SECSUB_RECT,
	SECSUB_QUAD,
	SECSUB_CSOLID,
	SECSUB_CTUBE,
	SECSUB_CHAN,
	SECSUB_I,
	SECSUB_Z,
	SECSUB_L,
	SECSUB_T,
	SECSUB_HATS,
	SECSUB_HREC,
	SECSUB_ASEC,
	SECSUB_MESH,
	SECSUB_UNKNOWN,
};

enum ANSYSSEC_LOC
{
	BEAM_CENT,
	BEAM_SHRC,
	BEAM_ORIGIN,
	BEAM_USER,
	SHELL_TOP,
	SHELL_MID,
	SHELL_BOT,
	SHELL_USER,
	LOC_UNKNOWN,
};

struct AnsysSection
{
	int id;
	ANSYSSEC_TYPE sType;
	ANSYSSEC_SUBTYPE subType;
	ANSYSSEC_LOC locType;
	std::string secName;
	double secData[12];
	double secControl[13];
	AnsysSection()
	{
		id = 0;
		sType = ANSYS_UNKNOWN;
		subType = SECSUB_UNKNOWN;
		locType = LOC_UNKNOWN;
		memset(secData, 0, sizeof(double) * 12);
		memset(secControl, 0, sizeof(double) * 13);
	}
};

struct AnsysKeyopt
{
	int id;
	int num;
	double val;
	AnsysKeyopt()
	{
		id = num = 0;
		val = DEFAUL_DBL;
	}
};

struct AnsysET
{
	AnsElemType::Type eType;
	int eid;
	bool ifOutPut;
	SimElem::Opt eleTechnology;
	int v[16];
	AnsysET()
	{
		eid = 0;
		eType = AnsElemType::UNKNOWN;
		ifOutPut = true;
		eleTechnology = SimElem::Opt::Opt_None;
		memset(v, 0, 16 * sizeof(int));
	}
};

struct AnsysCmBlock
{
	std::string cmName = "";
	int type = 0;     //! 0:Node;  1:Element
	std::vector<int> ids;
};

enum DIM_TYPE
{
	DIM_ARRAY,
	DIM_STRING,
	DIM_CHAR,
	DIM_TABLE,
	DIM_ARR4,
	DIM_ARR5,
	DIM_TAB4,
	DIM_TAB5,
	DIM_UNKNOWN,
};

struct AnsysDim
{
	std::string strName;
	DIM_TYPE dType;
	SNum3d v;
	std::unordered_map<std::string, std::string> vDimMap;
	AnsysDim()
	{
		strName.clear();
		dType = DIM_UNKNOWN;
		v.setValAll(0);
	}
};

const static std::string prefix_Section = "SEC";
const static std::string prefix_Set = "SET";
const static std::string prefix_Material = "MAT";
const static std::string prefix_Element = "ELE";
const static std::string prefix_Real = "REAL";
const static std::string prefix_BeamSec = "BIM";
const static std::string prefix_Dir = "DIR";

enum ANSYS_MAT_TYPE
{
	MAT_DENS = 0,
	MAT_EX,
	MAT_EY,
	MAT_EZ,
	MAT_PRXY,
	MAT_PRYZ,
	MAT_PRXZ,
	MAT_GXY,
	MAT_GYZ,
	MAT_GXZ,
	MAT_NUXY,
	MAT_NUYZ,
	MAT_NUXZ,
	MAT_ALPX,
	MAT_ALPY,
	MAT_ALPZ,
	MAT_CTEX,
	MAT_CTEY,
	MAT_CTEZ,
	MAT_THSX,
	MAT_THSY,
	MAT_THSZ,
	MAT_REFT,
	MAT_KXX,
	MAT_KYY,
	MAT_KZZ,
	MAT_C,

	MAT_CNT,
};

static ANSYS_MAT_TYPE GetAnsysMatType(std::string str)
{
	static std::unordered_map<std::string, ANSYS_MAT_TYPE> _gAnsysMapTxt = {
		{ "DENS",		MAT_DENS },
		{ "EX",			MAT_EX },
		{ "EY",			MAT_EY },
		{ "EZ",			MAT_EZ },
		{ "PRXY",		MAT_PRXY },
		{ "PRYZ",		MAT_PRYZ },
		{ "PRXZ",		MAT_PRXZ },
		{ "GXY",		MAT_GXY },
		{ "GYZ",		MAT_GYZ },
		{ "GXZ",		MAT_GXZ },
		{ "NUXY",		MAT_NUXY },
		{ "NUYZ",		MAT_NUYZ },
		{ "NUXZ",		MAT_NUXZ },
		{ "ALPX",		MAT_ALPX },
		{ "ALPY",		MAT_ALPY },
		{ "ALPZ",		MAT_ALPZ },
		{ "CTEX",		MAT_CTEX },
		{ "CTEY",		MAT_CTEY },
		{ "CTEZ",		MAT_CTEZ },
		{ "THSX",		MAT_THSX },
		{ "THSY",		MAT_THSY },
		{ "THSZ",		MAT_THSZ },
		{ "REFT",		MAT_REFT },
		{ "KXX",		MAT_KXX },
		{ "KYY",		MAT_KYY },
		{ "KZZ",		MAT_KZZ },
		{ "C",			MAT_C },
	};
	std::transform(str.cbegin(), str.cend(), str.begin(),
		[](unsigned char c) { return ::toupper(c); });
	auto it = _gAnsysMapTxt.find(str);
	if (it != _gAnsysMapTxt.end())
		return it->second;
	return MAT_CNT;
}

enum ANSYS_CONTACT_ALGORITHM
{
	AugmentedLagrangian,
	PenaltyFunction,
	MPC,
	CrossNormalTang, //! contact normal : Lagrange multiplier, tangent : penalty
	PureLagrangian   //! Lagrange multiplier on contact normal and tangent
};

enum ANSYS_CONTACT_LOCATION
{
	GaussPoint,
	NormalFromContactSurface,
	NormalToTargetSurface,
	NorNormalFromContactSurfaceStandard,
	NorNormalFromContactSurfaceShapeFunction,
	UnifiedApproach
};

enum ANSYS_CONTACT_CONSTRAINT
{
	ForceDistributedConstraint = 1,
	RigidSurfaceConstraint,
	CouplingConstraint
};

enum ANSYS_CONTACT_BEHAVIOR
{
	Standard,
	Rough,
	NoSeparationSliding,
	Bounded,
	NoSeparationAlways,
	BoundedAlways,
	BoundedIntial,
};

enum ANSYS_CONTACY_TYPE
{
	CONTA172,
	CONTA174,
	CONTA175,
	CONTA177,
	CONTA178,
};
struct Ansys_Contact
{
	Ansys_Contact()
	{}
	ANSYS_CONTACY_TYPE type;
	virtual ~Ansys_Contact()
	{

	}
};

struct Ansys_Contact174 :public Ansys_Contact
{
	int eleType = 0;
	ANSYS_CONTACT_ALGORITHM algorithm = AugmentedLagrangian;
	//ANSYS_CONTACT_LOCATION location = GaussPoint;
	ANSYS_CONTACT_BEHAVIOR behavior = Standard;
	ANSYS_CONTACT_CONSTRAINT constraint = RigidSurfaceConstraint;

	Ansys_Contact174()
	{
	};
	Ansys_Contact174(int eid)
	{
		eleType = eid;
	};
};

struct Ansys_Target170
{
	int eleType = 0;
	DIM_DOF dof = (DIM_DOF)(TX | TY | TZ | RX | RY | RZ);
	Ansys_Target170()
	{
	};
	Ansys_Target170(int eid)
	{
		eleType = eid;
	};
};

//新增node to surface接触单元代码
struct Ansys_Contact175 :public Ansys_Contact
{
	int eleType = 0;
	ANSYS_CONTACT_ALGORITHM algorithm = AugmentedLagrangian;
	//ANSYS_CONTACT_LOCATION location = GaussPoint;
	ANSYS_CONTACT_BEHAVIOR behavior = Standard;
	ANSYS_CONTACT_CONSTRAINT constraint = RigidSurfaceConstraint;

	Ansys_Contact175()
	{

	};
	Ansys_Contact175(int eid)
	{
		eleType = eid;
	};
};

enum TSHAPE_ELEMENT
{
	LINE,
	PARA,
	ARC,
	CARC,
	CIRC,
	TRIA,
	TRI6,
	QUAD,
	QUA8,
	CYLI,
	CONE,
	SOH3,
	PILO,
	POINT,
};

//新增代码
struct AnsysBuckle
{
	std::string method = "";
	int nMode = 1;
	double shift = 0.0;
	double ldmulte = 1000;
	std::string rangeKey = "CENTER";
};

//新增代码
struct AnsysModeMODOPT
{
	std::string method = "";
	int nMode = 6;
	int freqB = 0;
	int freqE = 10000;
	std::string cpxMod = "";
	std::string nrmKey = "";
	std::string modType = "";
	int blokSize = 0;
	std::string freqMod = "";
};

//新增EN数据结构
struct AnsysEN
{
public:
	int elementID;
	std::vector<int> nodeID;
	int matNum;
	int realConstantNum;
	int typeNum;
	AnsysEN()
	{};
	AnsysEN(int eid) :elementID(eid)
	{
	};
};